package cn.shopping.core.manager.impl;

import cn.shopping.common.exception.CommonException;
import cn.shopping.common.lock.RedissonLockUtils;
import cn.shopping.core.manager.UploadInfoManager;
import jodd.io.FileUtil;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.tomcat.util.codec.EncoderException;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import utils.SystemInfoUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.Date;
import java.util.UUID;

/**
 * 描述:
 *
 * @author Zhanggq
 * @date 2019/4/8 14:13
 */
@Component
public class UploadInfoManagerImpl implements UploadInfoManager {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public String wrtie(MultipartFile multipartFile) {
        //获得本地存储路径
        String localPath = SystemInfoUtils.getLocalPath();
        //按照时间存储的相对路径
        String relativePath = DateFormatUtils.format(new Date(), "yyyy/MM/dd/HH/");
        //存储的文件名
        String uuidName = SystemInfoUtils.createUUIDName(multipartFile.getOriginalFilename());
//        //文件夹路径与生成路径逻辑相同
//        String dirFullPath = localPath + DateFormatUtils.format(new Date(), "yyyy/MM/dd/");
        File file = new File(localPath+relativePath);
        //创建文件夹
        if (!file.exists()) {
            file.mkdirs();
        }
        file = new File(localPath+relativePath+uuidName);
        if (file.exists()) {
            throw CommonException.exception("文件已经上传！");
        }
        try {
            multipartFile.transferTo(file);
        } catch (IOException ioe) {
            throw CommonException.exception("上传错误！");
        }
        return relativePath+uuidName;
    }

    @Override
    public String writeByBase64(String BaseStr){
        if (StringUtils.isEmpty(BaseStr)) { // 图像数据为空
            throw CommonException.exception("上传错误，上传图片为空。");
        }
        //获得本地存储路径
        String localPath = SystemInfoUtils.getLocalPath();
        //按照时间存储的相对路径
        String relativePath = DateFormatUtils.format(new Date(), "yyyy/MM/dd/HH/");
        //存储的文件名
        String uuidName = UUID.randomUUID().toString().replace("-", "")+".png";
        File file = new File(localPath+relativePath);
        //创建文件夹
        if (!file.exists()) {
            file.mkdirs();
        }
        BASE64Decoder decoder = new BASE64Decoder();
        OutputStream out = null;
        try {
            // Base64解码
            byte[] b = decoder.decodeBuffer(BaseStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            out = new FileOutputStream(localPath+relativePath+uuidName);
            out.write(b);
            out.flush();


        } catch (Exception e) {
            throw CommonException.exception("上传错误，base64图片上传失败。");
        }finally {
            IOUtils.closeQuietly(out);
        }
        return relativePath+uuidName;
    }

    @Override
    public String writeByByte(byte[] bytes,String fileName){
        //获得本地存储路径
        String localPath = SystemInfoUtils.getLocalPath();
        //按照时间存储的相对路径
        String relativePath = DateFormatUtils.format(new Date(), "yyyy/MM/dd/HH/");
        //存储的文件名
        String uuidName = SystemInfoUtils.createUUIDName(fileName);
//        //文件夹路径与生成路径逻辑相同
//        String dirFullPath = localPath + DateFormatUtils.format(new Date(), "yyyy/MM/dd/");
        File file = new File(localPath+relativePath);
        //创建文件夹
        if (!file.exists()) {
            file.mkdirs();
        }
        file = new File(localPath+relativePath+uuidName);
        if (file.exists()) {
            throw CommonException.exception("文件已经上传！");
        }
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(file);
            out.write(bytes);
        }catch (IOException ioe){
            throw CommonException.exception("上传错误！");
        }finally {
            IOUtils.closeQuietly(out);
        }
        return relativePath+uuidName;
    }

    @Override
    public InputStream read(String filePath) {
        String localPath = SystemInfoUtils.getLocalPath();
        String fullPath = localPath + filePath;
        File file = new File(fullPath);
        if (!file.exists()) {
            throw CommonException.exception("下载文件不存在！");
        }
        //文件路径错误，是文件夹
        if (file.isDirectory()) {
            throw CommonException.exception("文件夹不支持下载！");
        }
        try {
            return new FileInputStream(file);
        } catch (FileNotFoundException e) {
            throw CommonException.exception("读取文件失败！");
        }
    }

    @Override
    public InputStream readMp3(String filePath) {
        String localPath = SystemInfoUtils.getLocalPath();
        String fullPath = localPath + filePath;
        String pathName = fullPath.substring(0,fullPath.indexOf("."));
        String mp3Path = pathName+".mp3";

        File file = new File(mp3Path);
        //amr文件转为mp3
        try {
            if (!file.exists()){
                //加锁
                RedissonLockUtils.lock("FFMPEG",5);
                changeAmr2Mp3(fullPath,mp3Path);
                //解锁
                RedissonLockUtils.unlock("FFMPEG");
            }
        } catch (EncoderException e) {
            throw CommonException.exception("读取文件失败！");
        }

        if (!file.exists()) {
            throw CommonException.exception("下载文件不存在！");
        }
        //文件路径错误，是文件夹
        if (file.isDirectory()) {
            throw CommonException.exception("文件夹不支持下载！");
        }
        try {
            return new FileInputStream(file);
        } catch (FileNotFoundException e) {
            throw CommonException.exception("读取文件失败！");
        }
    }

    @Override
    public void resizeImg(File fromFile, File toFile, double outputWidth) {
        try {
            //ImageIO支持的类型jpg,BMP,bmp,JPG,jpeg,wbmp,png,JPEG,PNG,WBMP,GIF,gif
            BufferedImage bi2 = ImageIO.read(fromFile);
            int newWidth;
            int newHeight;
            // 为等比缩放计算输出的图片宽度及高度
            double rate = ((double) bi2.getWidth(null)) / outputWidth + 0.1;
            newWidth = (int) (((double) bi2.getWidth(null)) / rate);
            newHeight = (int) (((double) bi2.getHeight(null)) / rate);
            BufferedImage to = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = to.createGraphics();
            to = g2d.getDeviceConfiguration().createCompatibleImage(newWidth, newHeight);
            g2d.dispose();
            g2d = to.createGraphics();
            @SuppressWarnings("static-access")
            Image from = bi2.getScaledInstance(newWidth, newHeight, bi2.SCALE_AREA_AVERAGING);
            g2d.drawImage(from, 0, 0, null);
            g2d.dispose();
            ImageIO.write(to, "jpg", toFile);
        } catch (Exception e) {
            logger.info("图片尺寸转换失败：",fromFile.getPath());
            throw CommonException.exception("图片尺寸转换失败！");
        }
    }

    @Override
    public double getWidth(String filePath) {
        double width = 0;
        try {
            InputStream is = new FileInputStream(filePath);
            BufferedImage buff = ImageIO.read(is);
            width = buff.getWidth();
            is.close(); //关闭Stream
        } catch (Exception e) {
            throw CommonException.exception("获取图片宽度失败！");
        }
        return width;
    }

    @Override
    public Long getSize(File file) {
        FileChannel fc = null;
        Long size = 0L;
        if(file.exists() && file.isFile()){
            FileInputStream fs = null;
            try {
                fs = new FileInputStream(file);
                fc = fs.getChannel();
                size = fc.size();
            } catch (FileNotFoundException e) {
                throw CommonException.exception("获取文件大小时文件未找到！");
            } catch (IOException e) {
                throw CommonException.exception("获取文件大小失败!");
            }finally {
                IOUtils.closeQuietly(fs);
            }
        }
        return size;
    }

    private void changeAmr2Mp3(String sourcePath, String targetPath) throws IllegalArgumentException, EncoderException {
        String webroot = getFfmpegPath();
        Runtime run = null;
        try {
            run = Runtime.getRuntime();
            long start=System.currentTimeMillis();
            System.out.println(new File(webroot).getAbsolutePath());
            //若文件已经存在则直接返回
            if (new File(targetPath).exists()){
                return;
            }
            //先生成临时文件
            String tempPath = targetPath.substring(0,targetPath.indexOf("."))+"-temp.mp3";
            //执行ffmpeg.exe,前面是ffmpeg.exe的地址，中间是需要转换的文件地址，后面是转换后的文件地址。-i是转换方式，意思是可编码解码，mp3编码方式采用的是libmp3lame
            Process p=run.exec(new File(webroot).getAbsolutePath()+"/ffmpeg -i "+new File(sourcePath).getAbsolutePath()+" "+new File(tempPath).getAbsolutePath());
            System.out.println(new File(webroot).getAbsolutePath()+"/ffmpeg -i "+new File(sourcePath).getAbsolutePath()+" "+new File(tempPath).getAbsolutePath());
            p.waitFor();
            //转换成功够将临时文件复制到目标文件
            FileUtil.copy(tempPath,targetPath);
            //删除临时文件
            File tempFile = new File(tempPath);
            tempFile.delete();
            //释放进程
            p.getInputStream().close();
            p.getErrorStream().close();
            p.getOutputStream().close();
            long end=System.currentTimeMillis();
            System.out.println(sourcePath+" convert success, costs:"+(end-start)+"ms");
        } catch (Exception e) {
            throw CommonException.exception("amr转MP3失败！");
        }finally{
            //run调用lame解码器最后释放内存
            if(run != null){
                run.freeMemory();
            }
        }
    }
    private String getFfmpegPath() {
        String localPath;
        if (SystemInfoUtils.isWindowPlatform()) {
            localPath = "D:\\ffmpeg\\bin";
        } else {
            localPath = "/var/ffmpeg_build/bin";
        }
        File file = new File(localPath);
        //不存在路径
        if (!file.exists()) {
            file.mkdirs();
        }
        return localPath;
    }

    @Override
    public String pictureAsBase64(InputStream inputStream){
        byte[] data = null;
        try {
            data = new byte[inputStream.available()];
            inputStream.read(data);
        } catch (IOException e) {
            throw CommonException.exception("图片转换Base64失败！");
        }finally {
            IOUtils.closeQuietly(inputStream);
        }
        // 加密
        BASE64Encoder encoder = new BASE64Encoder();
        String pictureAsBase64 = encoder.encode(data);
        return pictureAsBase64;
    }

}

